package moduloEstandares;

import conexion.ManejadorConexion;
import java.lang.reflect.Method;
import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import pojos.Areas;
import pojos.CatApartados;
import pojos.CatEstandares;
import pojos.CatReactivos;
import pojos.CatSubApartados;
import pojos.CatTemas;

/**
 *
 * @author Diego Andrés Gomez Montesinos
 */
public class ManejadorEstandares {
    
    ManejadorConexion servicioConexion;
    
    public ManejadorEstandares(ManejadorConexion servicioDeConexion) {
        servicioConexion = servicioDeConexion;
    }
    
    public CatEstandares getEstandarPorId(int idEstandar) {
        return (CatEstandares) servicioConexion.session.load(CatEstandares.class, idEstandar);
    }
    
    public List getFullEstandares() {
        String query = "FROM CatEstandares";
        return servicioConexion.ejecutaBusquedaHQL(query);
    }
    
    public CatApartados getApartadoPorId(int idApartado) {
        return (CatApartados) servicioConexion.session.load(CatApartados.class, idApartado);
    }
    
    public List getFullApartados() {
        String query = "FROM CatApartados";
        return servicioConexion.ejecutaBusquedaHQL(query);
    }
    
    public CatSubApartados getSubApartadoPorId(int idSubApartado) {
        return (CatSubApartados) servicioConexion.session.load(CatSubApartados.class, idSubApartado);
    }
    
    public List getFullSubApartados() {
        String query = "FROM CatSubApartados";
        return servicioConexion.ejecutaBusquedaHQL(query);
    }
 
    public CatTemas getTemaPorId(int idTema) {
        return (CatTemas) servicioConexion.session.load(CatTemas.class, idTema);
    }
    
    public List getFullTemas() {
        String query = "FROM CatTemas";
        return servicioConexion.ejecutaBusquedaHQL(query);
    }
    
    public CatReactivos getReactivoPorId(int idReactivo) {
        return (CatReactivos) servicioConexion.session.load(CatReactivos.class, idReactivo);
    }
    
    public List getFullReactivos() {
        String query = "FROM CatReactivos";
        return servicioConexion.ejecutaBusquedaHQL(query);
    }
    
    public List getReactivosPorTema(int idTema) {
        String query = "FROM CatReactivos WHERE catTemas = " + idTema;
        return servicioConexion.ejecutaBusquedaHQL(query);
    }
    
    public Object[] getReactivosPorArea(Areas area) {
        Object[] reactivos = area.getReactivos().toArray();
        return mergeSort(reactivos);
    }
    
    public boolean tieneApartados(CatEstandares estandar) {
        Object[] apartados = estandar.getCatApartados().toArray();
        if(apartados.length != 0) {
            if(((CatApartados) apartados[0]).getIdEnCata() == 0) {
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    }

    public boolean tieneSubApartados(CatEstandares estandar) {
        if(!tieneApartados(estandar)) {
            return false;
        }
        Object[] apartados = estandar.getCatApartados().toArray();
        Object[] subApartados = ((CatApartados) apartados[0]).getCatSubApartados().toArray();
        if(subApartados.length != 0) {
            if(((CatSubApartados) subApartados[0]).getIdEnCata() == 0) {
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    }    
    
    public DefaultTreeModel creaArbolDeEstandar(CatEstandares estandar) {
        
        DefaultMutableTreeNode nodoDeEstandar = new DefaultMutableTreeNode(estandar);
        DefaultTreeModel modeloArbol = new DefaultTreeModel(nodoDeEstandar);
        
        boolean tieneApartados = tieneApartados(estandar);
        boolean tieneSubApartados = tieneSubApartados(estandar);
        
        Object[] apartados = mergeSort(estandar.getCatApartados().toArray());
        for(int i = 0; i < apartados.length; i++) {
            CatApartados apartadoActual = (CatApartados) apartados[i];
            DefaultMutableTreeNode nodoApartado = new DefaultMutableTreeNode(apartadoActual);
            if(tieneApartados) {
                modeloArbol.insertNodeInto(nodoApartado, nodoDeEstandar, i);
            }
            Object[] subApartados = mergeSort(apartadoActual.getCatSubApartados().toArray());
            for(int j = 0; j < subApartados.length; j++) {
                CatSubApartados subApartadoActual = (CatSubApartados) subApartados[j];
                DefaultMutableTreeNode nodoSubApartado = new DefaultMutableTreeNode(subApartadoActual);
                if(tieneSubApartados) {
                    modeloArbol.insertNodeInto(nodoSubApartado, nodoApartado, j);
                }
                Object[] temas = mergeSort(subApartadoActual.getCatTemas().toArray());
                for(int k = 0; k < temas.length; k++) {
                    CatTemas temaActual = (CatTemas) temas[k];
                    DefaultMutableTreeNode nodoTema = new DefaultMutableTreeNode(temaActual);
                    if(!tieneApartados) {
                        modeloArbol.insertNodeInto(nodoTema, nodoDeEstandar, i);
                    } else {
                        if(!tieneSubApartados) {
                            modeloArbol.insertNodeInto(nodoTema, nodoApartado, i);
                        } else {
                            modeloArbol.insertNodeInto(nodoTema, nodoSubApartado, k);
                        }
                    }
                }
            }
        }
        
        return modeloArbol;
    }
    
    private Object[] mergeSort(Object[] elements) {
        int n = elements.length;
        Object[] elems = new Object[n];
        System.arraycopy(elements, 0, elems, 0, n);
        if(n > 1) {
            int m = n/2;
            Object[] elems1 = new Object[m];
            Object[] elems2 = new Object[n-m];
            System.arraycopy(elems, 0, elems1, 0, m);
            System.arraycopy(elems, m, elems2, 0, n-m);
            elems = merge(mergeSort(elems1), mergeSort(elems2));
        }
        return elems;
    }
    
    private Object[] merge(Object[] A, Object[] B) {
        Object[] elements = new Object[A.length + B.length];
        int idxA = 0;
        int idxB = 0;
        while(idxA+idxB != elements.length) {
            if(idxB == B.length) {
                elements[idxA + idxB] = A[idxA];
                idxA++;
            } else {
                if(idxA == A.length) {
                    elements[idxA+idxB] = B[idxB];
                    idxB++;
                } else {
                    int idA = 0;
                    int idB = 0;
                    try {
                        Method metodoGetId = A[idxA].getClass().getMethod("getIdEnCata", (Class<?>[]) null); 
                        idA = ((Integer) metodoGetId.invoke(A[idxA], (Object[]) null)).intValue();
                        idB = ((Integer) metodoGetId.invoke(B[idxB], (Object[]) null)).intValue();
                    } catch(Exception e) {
                        e.printStackTrace();
                    }
                    if(idA < idB) {
                        elements[idxA+idxB] = A[idxA];
                        idxA++;
                    } else {
                        elements[idxA+idxB] = B[idxB];
                        idxB++;
                    }
                }
            }
        }
        return elements;
    }
    
}